package com.rslai.base.tool.servertest.intercept;

import com.rslai.base.tool.servertest.command.CallStepCommand;
import com.rslai.base.tool.servertest.command.StepCommand;
import com.rslai.base.tool.servertest.context.Context;
import com.rslai.base.tool.servertest.model.KeyValueStore;
import com.rslai.base.tool.servertest.response.Response;
import com.rslai.base.tool.servertest.transport.command.HttpExecuteCommand;
import com.rslai.base.tool.servertest.util.ParameterUtils;
import com.rslai.base.tool.servertest.util.ReflectionUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RestfulApiInterceptor implements StepCommandInterceptor {
    private static final Pattern pattern = Pattern.compile("\\{([A-Za-z]+)\\}");

    public Object beforeExecute(StepCommand command, Response preResult, Context context) {
        if (!(command instanceof CallStepCommand)) return preResult;

        Object executeCommand = ReflectionUtils.getValue(command, "command");
        if (!(executeCommand instanceof HttpExecuteCommand)) return preResult;

        String url = (String) ReflectionUtils.getValue(executeCommand, "url");
        List parametersInUrl = extractParameters(url);
        if (parametersInUrl.isEmpty()) return preResult;

        List commandParameters = (List) ReflectionUtils.getValue(command, "params");
        commandParameters = ParameterUtils.prepareParameters(commandParameters, preResult, context);
        url = replace(url, commandParameters, parametersInUrl);

        commandParameters = removeUsedParameters(commandParameters, parametersInUrl);
        executeCommand = clone(executeCommand);
        ReflectionUtils.setFieldValue(executeCommand, "url", url);
        ReflectionUtils.setFieldValue(command, "params", commandParameters);
        ReflectionUtils.setFieldValue(command, "command", executeCommand);

        return preResult;
    }

    private Object clone(Object executeCommand) {
        return new HttpExecuteCommand((String) ReflectionUtils.getValue(executeCommand, "id"), "", (String) ReflectionUtils.getValue(executeCommand, "method"), (String) ReflectionUtils.getValue(executeCommand, "desc"));
    }

    private List<KeyValueStore> removeUsedParameters(List<KeyValueStore> params, List<String> parameterNames) {
        List newParams = new ArrayList(params);
        for (String key : parameterNames) {
            remove(newParams, key);
        }
        return newParams;
    }

    private void remove(List<KeyValueStore> params, String key) {
        Iterator iterator = params.iterator();
        while (iterator.hasNext()) {
            KeyValueStore keyValueStore = (KeyValueStore) iterator.next();
            if (keyValueStore.getName().equals(key))
                iterator.remove();
        }
    }

    private String replace(String url, List<KeyValueStore> params, List<String> parameterNames) {
        for (String name : parameterNames) {
            String value = get(params, name);
            url = url.replace(String.format("{%s}", new Object[]{name}), value);
        }
        return url;
    }

    private String get(List<KeyValueStore> params, String key) {
        for (KeyValueStore param : params) {
            if (param.getName().equals(key)) return (String) param.getValue();
        }
        return "";
    }

    protected static List<String> extractParameters(String url) {
        Matcher matcher = pattern.matcher(url);
        ArrayList result = new ArrayList();
        while (matcher.find()) {
            result.add(matcher.group(1));
        }
        return result;
    }

    public Object afterExecute(StepCommand command, Response response, Context context) {
        return response;
    }
}
